#include "util/AutoMem.h"
#include <string.h>
#include <memory>

#ifdef TRACE_WZAUTOMEM_OBJECT_COUNT
int CWZAutoMem::m_nRefCount = 0;
#endif

int CWZAutoMem::ReadInt(bool bLowBit)
{
    int n = 0;
    if (bLowBit){
        Read(&n,4);
    }else{
        n = (((int)ReadByte()) << 24) | (((int)ReadByte()) << 16) | (((int)ReadByte()) << 8) | ReadByte();
    }
    return n;
}

LONGLONG CWZAutoMem::ReadLongLong()
{
    LONGLONG n= 0;
    Read(&n,8);
    return n;
}

short CWZAutoMem::ReadShort(bool bLowBit)
{
    short n = 0;
    if (bLowBit)
    {
        Read(&n,2);
    }else{
        n = (((short)ReadByte()) << 8) | ReadByte();
    }
    return n;
}

USHORT CWZAutoMem::ReadUShort(bool bLowBit)
{
    USHORT n = 0;
    if (bLowBit)
    {
        Read(&n,2);
    }else{
        n = (((short)ReadByte()) << 8) | ReadByte();
    }
    return n;
}

BYTE CWZAutoMem::ReadByte()
{
    BYTE n = 0;
    Read(&n, 1);
    return n;
}

std::string CWZAutoMem::ReadLenString()
{
    if (GetNoUseLen() < 2){
        return "";
    }
    int nLen = ReadUShort();
    if (nLen == 0xffff){
        nLen = ReadInt();
    }
    if (GetNoUseLen() < nLen){
        return "";
    }
    std::string str;
    str.assign((char*)GetCurBuffer(), nLen);
    Seek(nLen);
    return str;
}

void CWZAutoMem::WriteLenString(const char* lpsz)
{
    int nStrLen = strlen(lpsz);
    int nLen = nStrLen;
    if (nStrLen >= 0xffff){
        if (GetNoUseLen() < nLen + 6){
            ChgLenAndSeek(nLen + 6 + GetCurSeek(), GetCurSeek());
        }
        WriteUSHORT(0xffff);
        WriteInt(nStrLen);
    }else{
        if (GetNoUseLen() < nLen + 2){
            ChgLenAndSeek(nLen + 2 + GetCurSeek(), GetCurSeek());
        }
        WriteUSHORT(nStrLen);
    }
    Write(lpsz, nLen);
}


BOOL CWZAutoMem::ChgLenAndSeek(int nNewLen, int nSeekFromBegin)
{
    if (ChgLen(nNewLen)){
        Seek(nSeekFromBegin, begin);
        return TRUE;
    }
    return FALSE;
}

BOOL CWZAutoMem::Copy(CWZAutoMem *pMem) {
    if (FALSE == pMem->ChgLen(GetLen())) {
        ASSERT(FALSE);
        return FALSE;
    }
    pMem->Write(GetBuffer(), GetLen());
    pMem->SeekToBegin();
    return TRUE;
}

CWZAutoMem *CWZAutoMem::Clone()
{
    CWZAutoMem *p = new CWZAutoMem(GetLen(), TRUE, false);
    p->Write(GetBuffer(), GetLen());
    p->Seek(GetCurSeek(), begin);
    return p;
}

std::shared_ptr<CWZAutoMem> CWZAutoMem::NewMem(int nLen)
{
    std::shared_ptr<CWZAutoMem> pMem(new CWZAutoMem(nLen, TRUE, false));
    pMem->SetLessMem(32);
    return pMem;
}

std::shared_ptr<CWZAutoMem> CWZAutoMem::NewMem(const void *buf, int nLen)
{
    std::shared_ptr<CWZAutoMem> pMem = NewMem(nLen);
    pMem->SeekToBegin();
    pMem->Write(buf, nLen);
    pMem->SeekToBegin();
    return pMem;
}

CWZAutoMem::CWZAutoMem(int len, BOOL bDelete, BOOL bZero)
{
    m_bDelete = TRUE;
    m_bZero = bZero;
    m_nLen = 0;
    m_pBuffer = NULL;
    m_nNewLen = 0;				//实际分配的内存。
    m_nMemLess = 0;				//相差多少内存要重新分配。
    Init(len, bDelete);

#ifdef TRACE_WZAUTOMEM_OBJECT_COUNT
    __sync_add_and_fetch(&m_nRefCount, 1);
#endif
}

CWZAutoMem::CWZAutoMem(const void *buffer, int len, bool bDelete, BOOL bZero)
{
    m_bDelete = TRUE;
    m_bZero = bZero;
    m_nLen = 0;
    m_pBuffer = NULL;
    m_nNewLen = 0;				//实际分配的内存。
    m_nMemLess = 0;				//相差多少内存要重新分配。
    Attach((void *)buffer, len ,bDelete);
#ifdef TRACE_WZAUTOMEM_OBJECT_COUNT
    __sync_add_and_fetch(&m_nRefCount, 1);
#endif
}

void CWZAutoMem::Init(int len, BOOL bDelete)
{
    Destory();
    if (len < 0) {
        ASSERT(FALSE);
        len = 0;
    }
    m_bDelete = bDelete;
    m_nLen = len;
    m_nSeek = 0;
    if (len == 0) {
        m_pBuffer = NULL;
        m_nNewLen = 0;
    } else {
        if (len % 4 != 0) {
            len += (4 - len % 4);
        }
        m_pBuffer = (BYTE*)malloc(len);//new BYTE[len];
        if (m_pBuffer == NULL) {
            m_nLen = 0;
            m_nNewLen = 0;
            ASSERT(FALSE);
        } else {
            if (m_bZero){
                memset(m_pBuffer, 0, len);
            }
            m_nNewLen = len;
        }
    }

}

CWZAutoMem::~CWZAutoMem()
{
#ifdef TRACE_WZAUTOMEM_OBJECT_COUNT
    __sync_sub_and_fetch(&m_nRefCount, 1);
#endif
    Destory();
}

void CWZAutoMem::SetLessMem(int n)
{
    m_nMemLess = n;
}

int CWZAutoMem::GetNewLen()
{
    return m_nNewLen;
}

int CWZAutoMem::SeekToBegin()
{
    m_nSeek = 0;
    return m_nSeek;
}

int CWZAutoMem::SeekToEnd()
{
    m_nSeek = m_nLen;
    return m_nSeek;
}

int CWZAutoMem::Seek(int nSeek, int nType)
{
    switch (nType) {
    case begin:
        m_nSeek = nSeek;
        break;
    case end:
        m_nSeek = m_nLen + nSeek;
        break;
    case current:
        m_nSeek += nSeek;
        break;
    default:
        ASSERT(FALSE);			//你调用时使用nType错误参数;
        break;
    }
    if ((m_nSeek >= 0) && (m_nSeek <= m_nLen)) {
        return m_nSeek;
    }
    //ASSERT(FALSE);
    if (m_nSeek < 0) {
        m_nSeek = 0;
    } else {
        m_nSeek = m_nLen;
    }
    //m_nSeek  = m_nSeek < 0 ? - m_nSeek: m_nSeek;
    //m_nSeek = nSeek > m_nLen ? m_nLen :m_nSeek;
    return m_nSeek;
}

BOOL CWZAutoMem::SeekToNextStr()
{
    if (m_pBuffer == NULL) {
        return FALSE;
    }
    while (m_nSeek < m_nLen) {
        if (*(m_pBuffer + m_nSeek) == 0) {
            m_nSeek++;
            return TRUE;
        }
        m_nSeek++;
    }
    SeekToEnd();
    return FALSE;
}

int CWZAutoMem::Write(const void *buffer, int len)
{
    if (m_nSeek + len > m_nLen) {
        int nWrite = m_nLen - m_nSeek;
        memcpy(m_pBuffer + m_nSeek, buffer, nWrite);
        m_nSeek = m_nLen;
        return nWrite;
    }
    memcpy(m_pBuffer + m_nSeek, buffer, len);
    m_nSeek += len;
    return len;
}

int CWZAutoMem::Read(void *buffer, int len)
{
    if (m_nSeek + len > m_nLen) {
        int nRead = m_nLen - m_nSeek;
        memcpy(buffer, m_pBuffer + m_nSeek , nRead);
        m_nSeek = m_nLen;
        return nRead;
    }
    memcpy(buffer, m_pBuffer + m_nSeek, len);
    m_nSeek += len;
    return len;
}

//把一段内存附加进来这个类..这个类里面的数据会按照以前的数据进行判断是否delete
//bDelete 当这个类销毁时,是否要delet这段内存.
int CWZAutoMem::Attach(const void *buffer, int len, BOOL bDelete)
{
    ASSERT(buffer);
    if (m_bDelete) {
        Destory();
    }
    if (len < 0) {
        ASSERT(FALSE);
        len = 0;
    }
    m_bDelete = bDelete;
    m_nLen = len;
    m_nSeek = 0;
    m_pBuffer = (BYTE *) buffer;
    m_nNewLen = m_nLen;
    return len;
}

BOOL CWZAutoMem::ZlibMem()
{
#ifdef MEM_ZLIB
    if (GetLen() < 50){	//这么短，不压缩
        return FALSE;
    }
    CWtMem mem(GetLen() + GetLen() /10 + 12, FALSE);
    mem.Write("zlib", 4);
    mem.WriteInt(GetLen());
    mem.WriteInt(GetLen());

    uLongf dest = mem.GetNoUseLen();
    int n = compress2(mem.GetCurBuffer(), &dest, GetBuffer(), GetLen(), 9);
    if (n == Z_BUF_ERROR){
        mem.SetDelete(TRUE);
        mem.ChgLen(mem.GetLen() + mem.GetLen()/2);
        mem.SetDelete(FALSE);
        dest = mem.GetNoUseLen();
        n = compress2(mem.GetCurBuffer(), &dest, GetBuffer(), GetLen(), 9);
    }

    if (n  != Z_OK){
        mem.SetDelete(TRUE);
        return FALSE;
    }

    Destory();
    Attach(mem.GetBuffer(), dest + 12, TRUE);
    SeekToBegin();
    Seek(8);
    WriteInt(dest);
    SeekToBegin();

#else
    ASSERT(FALSE);
    return FALSE;
#endif

    return TRUE;
}

BOOL CWZAutoMem::UnZlibMem()
{
#ifdef MEM_ZLIB

    if (GetLen()< 12){
        return TRUE;
    }
    SeekToBegin();
    if (memcmp("zlib", GetBuffer(), 4 )!= 0){
        return FALSE;
    }
    Seek(4);
    CWtMem mem(ReadInt(), FALSE);
    int nZlibSourceLen = ReadInt();
    ASSERT(GetNoUseLen() == nZlibSourceLen);
    uLongf dest = mem.GetLen();
    int ret = uncompress(mem.GetBuffer(), &dest, GetCurBuffer(), min(nZlibSourceLen, GetNoUseLen()));

    if (Z_OK != ret){
        ASSERT(FALSE);
        mem.SetDelete(TRUE);
        return FALSE;
    }

    Destory();
    Attach(mem.GetBuffer(), mem.GetLen());


#else
    ASSERT(FALSE);
#endif
    return TRUE;
}

void CWZAutoMem::Destory()
{
    if (m_bDelete) {
        if (m_pBuffer)
            free(m_pBuffer);
        //if (m_nLen == 1 && m_pBuffer != NULL) {
        //	delete m_pBuffer;
        //} else if (m_nLen > 1 && m_pBuffer != NULL) {
        //	delete[]m_pBuffer;
        //} else if (m_pBuffer != NULL) {
        //	delete m_pBuffer;
        //}
    } else {
        m_pBuffer = NULL;
    }
    m_pBuffer = NULL;
    m_nLen = 0;
    m_nSeek = 0;
    m_nNewLen = 0;

}


BOOL CWZAutoMem::ChgLen(int nNewLen, BOOL bDelNew)
{
    if (nNewLen == GetLen()) {
        SeekToBegin();
        return TRUE;
    }
    BOOL bNew = FALSE;
    if (m_nMemLess) {			//需要按这个长度倍数来分配内存
        if (m_nNewLen < nNewLen) {	//长度不足够
            bNew = TRUE;
        } else {
            if (m_nNewLen - nNewLen > m_nMemLess*2 && (m_nNewLen - nNewLen) > 64) {	//长度超出倍数范围,或者64字节内不重新分配
                bNew = TRUE;
            } else {
                bNew = FALSE;
            }
        }
    } else {
        int nNewMemery;
        nNewMemery = nNewLen % 4 ? nNewLen + 4 - nNewLen % 4 : nNewLen;
        if (m_nNewLen == nNewMemery) {	//长度足够,且剛剛，不會直超出長度。
            bNew = FALSE;
        } else {
            bNew = TRUE;
        }
    }

    if (bNew) {
        CWZAutoMem mem;
        int nMalloclen = nNewLen;
        if (m_nMemLess) {
            nMalloclen = nNewLen % m_nMemLess ? nNewLen + m_nMemLess - nNewLen % m_nMemLess : nNewLen;
        }
        mem.Init(nMalloclen, FALSE);
        SeekToBegin();
        Read(mem.GetBuffer(), wzmin(nNewLen, this->GetLen()));
        Destory();
        if (mem.GetLen()) {
            Attach(mem.GetBuffer(), nNewLen, bDelNew);
            m_nNewLen = nMalloclen;
        }
    } else {
        if (nNewLen > m_nLen) {
            if (m_bZero){
                memset(GetBuffer() + m_nLen, 0, nNewLen - m_nLen);
            }
        }
        if (nNewLen == 0) {
            Destory();
        }
        m_nLen = nNewLen;
        if (m_nSeek > nNewLen){
            SeekToEnd();
        }
        //this->SetDelete(bDelNew);
    }
    return TRUE;
}

//改变内存的顺序,倒序
void CWZAutoMem::ChgOrder(void *buffer, int len)
{
    char temp;
    for (int i = 0; i < len / 2; i++) {
        temp = *(((char *) buffer) + i);
        *(((char *) buffer) + i) = *(((char *) buffer) + len - i - 1);
        *(((char *) buffer) + len - i - 1) = temp;
    }
}

//查找下一段内存,找不到返回-1
int CWZAutoMem::FindNext(void *buffer, int len, BOOL bFindBegin)
{
    int nBegin = 0;
    if (!bFindBegin) {
        nBegin = m_nSeek;
    }
    while (nBegin + len <= m_nLen) {
        if (0 == memcmp(buffer, m_pBuffer + nBegin, len)) {
            return bFindBegin ? nBegin : (nBegin - m_nSeek);
        }
        nBegin++;
    }
    return -1;
}

BOOL CWZAutoMem::HasStringFromCur()
{
    BYTE byCharEnd = 0;
    if (-1 != FindNext(&byCharEnd, 1)) {
        return TRUE;
    }
    return FALSE;
}


void CWZAutoMem::OffestMem(void *buffer, int len, int offest)
{
    if (buffer == NULL) {
        ASSERT(FALSE);
        return;
    }
    if (len <= 0) {
        return;
    }

    BYTE *buf = (BYTE *) buffer;
#ifdef WIN32
    ::MoveMemory(buf + offest, buf , len );
#else
    memmove(buf + offest, buf, len);
#endif
    return;
    CWZAutoMem mem(len, TRUE);
    mem.Write(buffer, len);
    mem.SeekToBegin();
    mem.Read(buf + offest, len);
    return;

    if (offest < 0) {
        while (len-- > 0) {
            *(buf + offest) = *(buf);
            buf++;
        }
    } else if (offest > 0) {
        buf += len - 1;
        while (len-- > 0) {
            *(buf + offest) = *buf;
            buf--;
        }
    }
}

void CWZAutoMem::OffestCur(int nLen, int offest)
{
    if (m_nSeek + nLen + offest > m_nLen) {
        ASSERT(FALSE);
        return;
    }
    if (m_nSeek + offest < 0) {
        ASSERT(FALSE);
        return;
    }
    OffestMem(GetCurBuffer(), nLen, offest);
}


int CWZAutoMem::GetNoUseLen()
{
    return m_nLen - m_nSeek;
}

void CWZAutoMem::SetDelete(BOOL bDelete)
{
    m_bDelete = bDelete;
}

int CWZAutoMem::GetLen()
{
    return m_nLen;
}

int CWZAutoMem::GetCurSeek()
{
    return m_nSeek;
}

BYTE *CWZAutoMem::GetBuffer()
{
    return m_pBuffer;
}

BYTE *CWZAutoMem::GetCurBuffer()
{
    return (m_pBuffer + m_nSeek);
}

int CWZAutoMem::WriteByte(BYTE nByte)
{
    return Write(&nByte, 1);
}

int CWZAutoMem::WriteChar(char ch)
{
    return Write(&ch, 1);
}

int CWZAutoMem::WriteInt(int nInt)
{
    return Write(&nInt, 4);
}

int CWZAutoMem::WriteIntHL(int nInt)
{
    int nReturn = Write( ((BYTE*)&nInt)+3, 1);
    nReturn += Write( ((BYTE*)&nInt)+2, 1);
    nReturn += Write( ((BYTE*)&nInt)+1, 1);
    return nReturn + Write( ((BYTE*)&nInt), 1);
}

int CWZAutoMem::WriteUINT(UINT n)
{
    return Write(&n, 4);
}

int CWZAutoMem::WriteUSHORT(USHORT nUshort)
{
    return Write(&nUshort, 2);
}

int CWZAutoMem::WriteUSHORTHL(USHORT nUshort)
{
    int nReturn = Write( ((BYTE*)&nUshort)+1, 1);
    return nReturn + Write( ((BYTE*)&nUshort), 1);
}

int CWZAutoMem::WriteShort(short nShort)
{
    return Write(&nShort, 2);
}

int CWZAutoMem::WriteStr(const char* lpsz)
{
    return Write((void *)lpsz, (int)(strlen(lpsz)+1));
}

int CWZAutoMem::WriteData(unsigned long n)
{
    return Write(&n, 4);
}

int CWZAutoMem::WriteData(long n)
{
    return Write(&n, 4);
}

int CWZAutoMem::WriteData(BYTE nByte)
{
    return Write(&nByte, 1);
}

int CWZAutoMem::WriteData(char ch)
{
    return Write(&ch, 1);
}

int CWZAutoMem::WriteData(int nInt)
{
    return Write(&nInt, 4);
}

int CWZAutoMem::WriteData(UINT n)
{
    return Write(&n, 4);
}

int CWZAutoMem::WriteData(USHORT nUshort)
{
    return Write(&nUshort, 2);
}

int CWZAutoMem::WriteData(short nShort)
{
    return Write(&nShort, 2);
}

int CWZAutoMem::WriteData(const char* lpsz)
{
    return Write((void *)lpsz, (int)strlen(lpsz) + 1);
}

int CWZAutoMem::RepLace(void *bufferOld, void *buffernew, int len)
{
    //int nSeek = GetCurSeek();
    int nReturn = 0;
    int nFind = FindNext(bufferOld, len, TRUE);
    if (-1 != nFind) {
        do {
            nReturn++;
            Seek(nFind, CWZAutoMem::current);
            Write(buffernew, len);
            nFind = FindNext(bufferOld, len, FALSE);
        } while (nFind != -1);
    }
    Seek(m_nSeek, CWZAutoMem::begin);
    return nReturn;
}


int CWZAutoMem::WriteRand(int nSize)
{
    int nCout = nSize /2 ;
    int nReturn = 0;
    for (int i = 0; i < nCout ; i++){
        nReturn += WriteShort(rand() * rand());
    }
    nCout = nSize - nCout *2;
    for (int i = 0; i < nCout ; i++){
        nReturn += WriteByte(rand());
    }
    return nReturn;
}

BOOL CWZAutoMem::StartWith(const void *buf, int len)
{
    if (GetLen() < len){
        return FALSE;
    }
    return memcmp(m_pBuffer, buf, len) == 0;
}

int CWZAutoMem::WriteMust(const void *buf, int len)
{
    if (GetNoUseLen() < len){
        ChgLenAndSeek(GetCurSeek() + len, GetCurSeek());
    }
    return Write(buf, len);
}
